package com.fy.tt.action;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;

import com.alibaba.fastjson.JSONObject;
import com.fy.basejar.tool.ActionToolBase;
import com.fy.toolhelper.util.RequestUtils;
import com.fy.toolhelper.util.ResponseUtils;
import com.fy.tt.dao.ITemplateDao;
import com.fy.tt.dao.impl.TemplateDaoImpl;
import com.fy.tt.remote.service.ITemplateRemoteService;
import com.fy.tt.remote.service.impl.TemplateRemoteServiceImpl;
import com.fy.tt.service.ITemplateService;
import com.fy.tt.service.impl.TemplateServiceImpl;

/**
 * 工具模板
 * 注意: 建议使用alibaba的FastJson进行json解析. PS: 默认在lib包下了(lib存放各种非环境提供的依赖包).
 * 此项目结构中包除了工具主类(即这个类)不是都必须要的, 根据自己的工具业务增减.
 */
public class TemplateTool extends ActionToolBase {

	/*
	* 查询所有词汇
	* */
	@Action
	public Map<String,Object> getAllWords(HttpServletRequest request) throws Exception{
		return ResponseUtils.asResultAndMsg("data","msg");
	}



	
	@Action
	public Map<String, Object> doAction(HttpServletRequest request) throws Exception {
		return ResponseUtils.asResultAndMsg(true, "方法名称即Action名称, 根据onBeforeAct回调中如何获取Action值");
	}
	/**
	 * 对外提供调用的接口, 方法名称即Action名称, 根据onBeforeAct回调中如何获取Action值来传参.
	 */

	@Action
	public Map<String, Object> doSomeBussiness(HttpServletRequest
			/* RequestParameter 如果需要使得同时兼容有页面和无页面的调用接口可以使用这个, 
			 * 若是用RequestUtils获取参数, 下面的代码不用改 */ request) throws Exception {
		// 统一使用RequestUtils工具类获取参数
		String strParam = RequestUtils.getStringParameter(request, "strParam");
		Long longParam = RequestUtils.getLongParameter(request, "longParam");
		List<Long> longListParam = RequestUtils.getLongJsonArrayParameter(request, "longListParam");
		/* 其它的还有各种类型, 请开发者自己查看 */
		// 对于创建接口, 传入一个json对象的字符串解析, 也可以使用RequestUtils进行获取参数
		JSONObject jsonParam = JSONObject.parseObject(RequestUtils.getStringParameter(request, "jsonParam")) ;
		String someKey1 = jsonParam.getString("someKey");
		// 或
		String someKey2 = RequestUtils.getStringParameter(jsonParam, "someKey2");
		// 都可以.
		// 文档上传, 根据上传时表单中文档的key来获取, 没有key的暂时没有支持请自行实现
		FileItem fileItem = getUploadFile("fileKey");
		byte[] bytes = fileItem.get();
		// 所有的Bean都通过该静态方法获取. 由于是静态方法, 在Service实现类中也可以调用
		ITemplateService templateService = getBean(ITemplateService.class);
		// PS: 不过要使用工具类名称, 如TemplateTool.getBean, 如果不希望Service实现类耦合工具顶层类, 请使用ActionTool.getBean
		templateService.doSomeBussiness();
		// ResponseUtils规范了返回值格式(具体组合请自己查看), 方便前端统一处理
		return ResponseUtils.asResultAndMsg(true, "业务操作完成");
	};
	
	/**
	 * 返回值默认将该返回的对象处理为JSON对象.
	 *  如果有特殊需求, 使用resultHandler属性设置处理类即可, 如果返回值类型与可处理类型不一致会报错.
	 *还可以为Action设置别名(可以多个), 这样多个名称指向同一个Action处理接口就可以做到了, 注意不要和已有的重复即可, 否则报错.
	 */
	@Action(resultHandler = OtherResultHandler.class, aliases = {"aliasActionName"})
	public byte[] returnBytes(HttpServletRequest request) {
		return "".getBytes();
	};
	
	/**
	 * 获取暴露给前端的一些配置信息
	 */
	@Action
	public Map<String, Object> getConfigs() {
		// 建议如果需要向前端暴露一些后台的配置或运行环境信息时, 可以通过这样一个action接口来实现. 比如当前用户的具体信息等等.
		return new HashMap<String, Object>();
	};
	
	// 可以额外定义的环境变量
	private static final String GLB_KEY_OTHER_TOOL_ID = "GLB_KEY_OTHER_TOOL_ID";
	
	@Override
	protected void onLoadJsonConfig(GlobalContext context, JSONObject configParamJson) throws Exception {
		/* 对应加载config.xml中的toolConfig的内容, 必须是JSON才会进入此方法 */
		context.putGlobal(GLB_KEY_OTHER_TOOL_ID, configParamJson.getLong("otherToolID"));
	}
	
	/* 这里是特别需求的类声明 */

	/**
	 * 以特殊返回值类型byte[]为例子, 实例ResultHandler的使用, 在{@link Action#resultHandler()}中表明该类字节码即可
	 */
	private final static class OtherResultHandler implements ResultHandler<byte[]/*这里是Action返回值的类型*/> {
		@Override
		public Object handle(HttpServletRequest request, 
				HttpServletResponse response, byte[] source) throws Exception {
			response.setContentType("image/jpeg");
			response.setHeader("Prgama", "No-cache");
			// ...
			response.getOutputStream().write(source);
			response.flushBuffer();
			return null;
		}
	}
	
	/* 这里是模拟Spring管理Bean提供的类实例管理的声明部分(没有依赖注入的处理, 所以不要把要用到的Bean声明为类成员变量) 
	 * 所有用到的Bean都要声明, 否则报错, 并且强烈建议forClass为接口, 注意保持声明方法的返回值类型与forClass一致*/
	
	@BeanDeclare(forClass = ITemplateService.class, scope = BeanScope.TEMPORY)
	private ITemplateService onDeclaringTemplateService() {
		// 这样做的好处是保留开发者自定义初始化的编程能力, 当然简单实例化情况下这样写也挺麻烦的
		return new TemplateServiceImpl();
	}
	
	@BeanDeclare(forClass = ITemplateDao.class, scope = BeanScope.TEMPORY)
	private ITemplateDao onDeclaringTemplateDao() throws Exception {
		return new TemplateDaoImpl();
	}
	
	@BeanDeclare(forClass = ITemplateRemoteService.class, scope = BeanScope.GLOBAL)
	private ITemplateRemoteService onDeclaringTemplateRemoteService() {
		return new TemplateRemoteServiceImpl() {
			@Override
			protected Long getToolID() throws Exception {
				return (Long) getGlobal(GLB_KEY_OTHER_TOOL_ID);
			}
		};
	}

	/*
	* 对应的Service、Dao (RemoteService访问core接口获取相关信息)
	* */
}
